#include "../server.hpp"
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <regex>
#define DEFAULT_TIMEOUT 10
std::unordered_map<int,std::string> _statu_msg = {
    {100,	"Continue"},
    {101,	"Switching Protocols"},	                     
    {200,	"OK"},	
    {201,	"Created"}	,
    {202,	"Accepted"	},
    {203,	"Non-Authoritative Information"},
    {204,	"No Content"	},
    {205,	"Reset Content"	},
    {206,	"Partial Content"	},
    {300,	"Multiple Choices"	},
    {301,	"Moved Permanently"	},
    {302,	"Found"	},
    {303,	"See Other"	},
    {304,	"Not Modified"	},
    {305,	"Use Proxy"	},
    {306,	"Unused"	},
    {307,	"Temporary Redirect"	},
    {400,	"Bad Request"	},
    {401,	"Unauthorized"	},
    {402,	"Payment Required"	},
    {403,	"Forbidden"	},
    {404,	"Not Found"	},
    {405,	"Method Not Allowed"	},
    {406,	"Not Acceptable"	},
    {407,	"Proxy Authentication Required"	},
    {408,	"Request Time-out"	},
    {409,	"Conflict"	},
    {410,	"Gone"	},
    {411,	"Length Required"},
    {412,	"Precondition Failed"	},
    {413,	"Request Entity Too Large"	},
    {414,	"Request-URI Too Large"	},
    {415,	"Unsupported Media Type"	},
    {416,	"Requested range not satisfiable"	},
    {417,	"Expectation Failed"	},
    {500,	"Internal Server Error"	},
    {501,	"Not Implemented	"},
    {502,	"Bad Gateway"	},
    {503,	"Service Unavailable"	},
    {504,	"Gateway Time-out"},
    {505,	"HTTP Version not supported"}
};
std::unordered_map<std::string,std::string> _file_mimes = {
{".apk", "application/vnd.android.package-archive"},
{".avi", "video/x-msvideo"},
{".buffer", "application/octet-stream"},
{".cer", "application/pkix-cert"},
{".chm", "application/vnd.ms-htmlhelp"},
{".conf", "text/plain"},
{".cpp","text/x-c"},
{".crt", "application/x-x509-ca-cert"},
{".css", "text/css"},
{".csv", "text/csv"},
{".doc", "application/msword"},
{".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
{".exe", "application/x-msdownload"},
{".flac", "audio/x-flac"},
{".flv", "video/x-flv"},
{".gif", "image/gif"},
{".h263", "video/h263"},
{".h264", "video/h264"},
{".htm","text/html"},
{".html", "text/html"},
{".ico", "image/x-icon"},
{".ini", "text/plain"},
{".ink", "application/inkml+xml"},
{".iso", "application/x-iso9660-image"},
{".jar", "application/java-archive"},
{".java", "text/x-java-source"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".js", "application/javascript"},
{".json", "application/json"},
{".json5", "application/json5"},
{".jsx", "text/jsx"},
{".list", "text/plain"},
{".lnk", "application/x-ms-shortcut"},
{".log", "text/plain"},
{".m3u8", "application/vnd.apple.mpegurl"},
{".manifest", "text/cache-manifest"},
{".map", "application/json"},
{".markdown", "text/x-markdown"},
{".md", "text/x-markdown"},
{".mov", "video/quicktime"},
{".mp3", "audio/mpeg"},
{".mp4", "video/mp4"},
{".mpeg", "video/mpeg"},
{".mpg", "video/mpeg"},
{".msi", "application/x-msdownload"},
{".ogg", "audio/ogg"},
{".ogv", "video/ogg"},
{".otf", "font/opentype"},
{".pdf", "application/pdf"},
{".png", "image/png"},
{".ppt", "application/vnd.ms-powerpoint"},
{".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
{".psd", "image/vnd.adobe.photoshop"},
{".rar", "application/x-rar-compressed"},
{".rm", "application/vnd.rn-realmedia"},
{".rmvb", "application/vnd.rn-realmedia-vbr"},
{".roff", "text/troff"},
{".sass", "text/x-sass"},
{".scss", "text/x-scss"},
{".sh", "application/x-sh"},
{".sql", "application/x-sql"},
{".svg", "image/svg+xml"},
{".swf", "application/x-shockwave-flash"},
{".tar", "application/x-tar"},
{".text", "text/plain"},
{".torrent", "application/x-bittorrent"},
{".ttf", "application/x-font-ttf"},
{".txt", "text/plain"},
{".wav", "audio/x-wav"},
{".webm", "video/webm"},
{".wm", "video/x-ms-wm"},
{".wma", "audio/x-ms-wma"},
{".wmx", "video/x-ms-wmx"},
{".woff", "application/font-woff"},
{".woff2", "application/font-woff2"},
{".wps", "application/vnd.ms-works"},
{".xhtml", "application/xhtml+xml"},
{".xls", "application/vnd.ms-excel"},
{".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{".xml", "application/xml"},
{".xz", "application/x-xz"},
{".yaml", "text/yaml"},
{".yml", "text/yaml"},
{".zip", "application/zip"}
};
class Util{
public:
    static size_t Split(const std::string& src,const std::string& sep,std::vector<std::string>* arr) // 字符串分割
    {
        size_t offset = 0;
        while(offset < src.size()){
            size_t pos = src.find(sep,offset);
            if(pos == std::string::npos){
                arr->push_back(src.substr(offset));
                return arr->size();
            }
            if(pos - offset == 0) {
                offset = pos + sep.size();
                continue;
            }
            arr->emplace_back(src.substr(offset,pos-offset));
            offset = pos + sep.size();
        }
        return arr->size();
    }
    static bool ReadFile(const std::string& filename,std::string* buf) // 读取文件内容放到buffer中
    {
        std::ifstream ifs(filename,std::ios::binary);
        if(!ifs.is_open()){
            ERR_LOG("OPEN %s FILE ERR",filename.c_str());
            return false;
        }
        size_t fsize = 0;
        ifs.seekg(0,ifs.end); // 跳转读写位置到末尾
        fsize = ifs.tellg(); // 告知偏移量
        ifs.seekg(0,ifs.beg); // 设置偏移量
        buf->resize(fsize);
        ifs.read(&(*buf)[0],fsize);
        if (!ifs.good()){
            ERR_LOG("READ %s FILE ERR",filename.c_str());
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }
    static bool WriteFile(const std::string& filename,const std::string& buf) // 写入数据
    {
        std::ofstream ofs(filename,std::ios::binary|std::ios::trunc);
        if (!ofs.is_open()){
            ERR_LOG("OPEN %s FILE ERR",filename.c_str());
            return false;
        }
        ofs.write(buf.c_str(),buf.size());
        if(!ofs.good()){
            ERR_LOG("WRITE %s FILE ERR",filename.c_str());
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }
    static std::string UrlEncode(const std::string& url,bool convert_space_to_plus) // encode 避免ERL中资源路径与查询字符串中的特殊字符与HTTP请求中的特殊字符产生歧义
    // 编码格式：；将特殊字符的ascii值，转换为两个16禁止的字符 前缀% c++ -> c%20%20
    // 不编码的特殊字符：RFC3986 .-_~ 字母数字属于绝对不编码字符
    // W3C文档中固定，查询字符串' ' -> + 解码就是 + -> ' '
    {
        std::string res;
        for(const auto &ch : url){
            if(ch == '.' || ch == '-' || ch == '_' || ch == '~' || static_cast<bool>(isalnum(ch))){
                res += ch;
                continue;
            }else if(ch == ' ' && convert_space_to_plus){
                res += "+";
                continue;
            }
            // 转换为 %HH操作
            char tmp[4] = {0};
            snprintf(tmp,4,"%%%02X",ch);
            res += tmp;
        }
        return res;
    }
    static std::string UrlDecode(const std::string& url,bool convert_space_to_plus) // decode
    {
        // 遇到% 将后后面的2个字符转换为数字 nums[0] << 4 + nums[1]  
        std::string res;
        for(int i = 0; i < url.size();i++){
            if(url[i] =='+' && convert_space_to_plus){
                res += ' ';
                continue;
            }
            if(url[i] == '%' && i + 2 < url.size()){
                char v1 = HexToI(url[i+1]);
                char v2 = HexToI(url[i+2]);
                char v = (v1 << 4) + v2;
                res += v;
                i += 2;
            }else{
                res += url[i];
            }
        }
        return res;
    }
    
    static std::string StatusDesc(int statu) // 状态码信息的获取
    {
        
        auto it  = _statu_msg.find(statu);
        if(it != _statu_msg.end()){
            return it->second;
        }
        return "Unknow";
    }
    static std::string ExtMime(const std::string& filename) // 文件后缀获取mime
    {
        
        size_t pos = filename.rfind('.');
        if(pos == std::string::npos) return "application/octet-stream";
        std::string mime = filename.substr(pos);
        auto it = _file_mimes.find(mime);
        if(it != _file_mimes.end()){
            return it->second;
        }
        return "application/octet-stream";
    }
    static bool IsDirectory(const std::string& filename) // 是否为目录文件
    {
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if(ret < 0){
            DBG_LOG("%s",strerror(errno));
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    static bool IsRegular(const std::string& filename) // 是否为普通文件
    {
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if(ret < 0){
            // DBG_LOG("%s",strerror(errno));
            return false;
        }
        return S_ISREG(st.st_mode);
    }
    static bool VaildPath(const std::string& path) // http请求资源路径的有效性
    // /index.html -- 前面的/叫相对根目录 映射的是某个服务器的子目录
    // 客户端只能请求相对根目录中的资源，其他地方的资源不予理会
    // /../index.html 这个路径会跑到相对根目录之外，不合理，错误
    {
        // 思想：按照/进行路径分割，根据有多少子目录，计算目录深度，有多少层，深度只能为1
        std::vector<std::string> subdir;
        int level = 0;
        Split(path,"/",&subdir);
        for(auto& dir:subdir){
            if(dir == ".") continue;
            if(dir == ".."){
                level--; // 任意一层小于0，认为有问题
                if(level < 0)
                    return false;
                continue;
            }
            level++;
        }
        return true;
    }
private:
    static char HexToI(char c){
        if(isdigit(c))
            return c - '0';
        else if (islower(c))
            return c - 'a' + 10;
        else if (isupper(c))
            return c - 'A' + 10;
        return -1;
    }
};

class HttpRequest{
public:
    std::string _method;
    std::string _path;
    std::string _version;
    std::string _body;
    std::smatch _matches; // url提取字段
    std::unordered_map<std::string,std::string> _headers; // 头部字段
    std::unordered_map<std::string,std::string> _params; // 查询字符串
public:
    HttpRequest():_version("HTTP/1.1") {}
    void ReSet() {
        _method.clear();
        _path.clear();
        _version = "HTTP/1.1";
        _body.clear();
        std::smatch match;
        _matches.swap(match);
        _headers.clear();
        _params.clear();
    } 
    void SetHeader(const std::string& key,const std::string& value)
    {
        _headers[key] = value;
    }
    bool HasHeader(const std::string& key)
    {
        return _headers.find(key) != _headers.end();
    }
    std::string GetHeader(const std::string& key)
    {
        auto it = _headers.find(key);
        if(it != _headers.end()) {
            return it->second;
        }
        return "";
    }
    void SetParams(const std::string& key,const std::string& value)
    {
        _params.insert({key,value});
    }
    bool HasParams(const std::string& key)const
    {
        return _params.find(key) != _params.end();
    }
    std::string GetParams(const std::string& key)const
    {
        auto it = _params.find(key);
        if(it != _params.end()){
            return it->second;
        }
        return "";
    }
    size_t ContentLength(const std::string& key="Content-Length")
    {
        // Content-Length:123\r\n
        if(HasHeader(key))
            return atoi(GetHeader(key).c_str());
        return 0;
    }
    bool Close() // 判断是否是长连接或短链接
    {
        const std::string key = "Connection";
        // DBG_LOG("%d",HasHeader(key));
        // DBG_LOG("%d",GetHeader(key) == "keep-alive");
        // DBG_LOG("%s",GetHeader(key).c_str());
        if(HasHeader(key) && GetHeader(key) == "keep-alive")
            return false;
        return true;
    }
};

class HttpResponse{
public:
    int _statu;    
    std::string _body;
    bool _redirect_flag;
    std::string _redirect_url;
    std::unordered_map<std::string,std::string> _headers;
public:

    HttpResponse():_redirect_flag(false),_statu(200) {}
    HttpResponse(int statu):_redirect_flag(false),_statu(statu) {}
    void ReSet()
    {
        _statu = 200;
        _body.clear();
        _redirect_flag =false;
        _redirect_url.clear();
        _headers.clear();
    }
    void SetHeader(const std::string& key,const std::string& value)
    {
        _headers.insert({key,value});
    }
    bool HasHeader(const std::string& key)
    {
        return _headers.find(key) != _headers.end();
    }
    std::string GetHeader(const std::string& key)
    {
        if(HasHeader(key))
            return _headers.at(key);
        return "";
    }
    void SetContent(const std::string& body,const std::string& type="text/html")
    {
        _body = body;
        SetHeader("Content-Type",type);
    }
    void SetRedirect(const std::string& url,int statu=302)
    {
        _redirect_flag = true;
        _redirect_url = url;
        _statu=statu;
    }
    bool Close() // 判断是否是长连接或短链接
    {
        const std::string key = "Connection";
        if(HasHeader(key) && GetHeader(key) == "keep-alive")
            return false;
        return true;
    }
};
#define MAX_LENGTH 8192 
typedef enum {
    RECV_HTTP_ERR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
} HttpRecvStatu;
class HttpContext{
private:
    int _resp_statu; // 响应状态码
    HttpRecvStatu _recv_statu; // 当前解析的阶段信息
    HttpRequest _request;
private:
    bool RecvHttpLine(Buffer* buf)
    {
        if(_recv_statu != RECV_HTTP_LINE) return false;
        // 获取一行数据
        std::string line = buf->GetLineAndPop();
        // 需要考虑的要素，缓冲区中的数据不足一行，获取一行的数据很长
        if(line.size() == 0){
            // 缓冲区中的数据不足一行，则需要判断缓冲区中的刻度数据的长度，如果很长了且不与一行
            if(buf->ReadAbleSize() > MAX_LENGTH){
                _recv_statu = RECV_HTTP_ERR;
                _resp_statu = 414; // uri to long
                return false;
            }
            // 缓冲区中数据不足一行，但是不多，可以等待新的数据
            return true;
        }
        if(line.size() > MAX_LENGTH){
            _recv_statu = RECV_HTTP_ERR;
            _resp_statu = 414; // uri to long
            return false;
        }
        return ParseHttpLine(line);
    }
    bool ParseHttpLine(const std::string& str){
        std::smatch matches;
        std::regex pattern("(GET|POST|PUT|DELETE|HEAD) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?",std::regex::icase);
        bool ret = std::regex_match(str,matches,pattern);
        if(ret == false){
            _recv_statu = RECV_HTTP_ERR;
            _resp_statu = 400; // bad request
            return false;
        }
        // for(int i = 0; i < matches.size();i++){
        //     printf("matches[%d] = [%s]\n",i,matches[i].str().c_str());
        // }
        _request._method = matches[1].str();
        std::transform(_request._method.begin(),_request._method.end(),_request._method.begin(),::toupper);
        // 需要对url进行解码
        _request._path = Util::UrlDecode(matches[2].str(),false);
        _request._version = matches[4].str();
        std::vector<std::string> query_string_arr;
        std::string query_string = matches[3].str();
        Util::Split(query_string,"&",&query_string_arr);
        for(auto& str : query_string_arr){
            std::vector<std::string> ans;
            Util::Split(str,"=",&ans);
            if(ans.size() != 2) {
                 _recv_statu = RECV_HTTP_ERR;
                _resp_statu = 400; // bad request
                return false;
            }
            _request.SetParams(Util::UrlDecode(ans[0],true),Util::UrlDecode(ans[1],true));
        }
        _recv_statu = RECV_HTTP_HEAD;
        return true;
    }
    bool RecvHttpHead(Buffer* buf)
    {
        if(_recv_statu != RECV_HTTP_HEAD) return false;
        // 一行一行取出数据，直到遇到空行为止 key:val\r\nkey:val\r\n
        while(1){
            // 获取一行数据
            std::string line = buf->GetLineAndPop();
            // 需要考虑的要素，缓冲区中的数据不足一行，获取一行的数据很长
            if(line.size() == 0){
                // 缓冲区中的数据不足一行，则需要判断缓冲区中的刻度数据的长度，如果很长了且不与一行
                if(buf->ReadAbleSize() > MAX_LENGTH){
                    _recv_statu = RECV_HTTP_ERR;
                    _resp_statu = 414; // uri to long
                    return false;
                }
                // 缓冲区中数据不足一行，但是不多，可以等待新的数据
                return true;
            }
            if(line.size() > MAX_LENGTH){
                _recv_statu = RECV_HTTP_ERR;
                _resp_statu = 414; // uri to long
                return false;
            }
            if(line == "\n" || line == "\r\n"){
                break;
            }
            bool ret = ParseHttpHead(line);
            if(!ret) return false;
        }
        _recv_statu = RECV_HTTP_BODY;
        return true;
    }
    bool ParseHttpHead(std::string& line)
    {
        // key:val\r\nkey:val\r\n
        // 前面居然有个空格，虽然不懂但是打手震撼
        int i = 0;
        for(; i < line.size();i++){
            if(line[i] != ' ')
                break;
        }
        if(line.back() == '\n') line.pop_back();
        if(line.back() == '\r') line.pop_back();
        size_t pos = line.find(": ");
        if(pos == std::string::npos){
             _recv_statu = RECV_HTTP_ERR;
            _resp_statu = 400; // bad request
            return false;
        }
        std::string key = line.substr(i,pos-i);
        std::string value = line.substr(pos+2);
        // DBG_LOG("[%s: %s]",key.c_str(),value.c_str());
        _request.SetHeader(key,value);
        // DBG_LOG("---[%s: %s]",key.c_str(),_request._headers.at(key).c_str());
        return true;
    }
    bool RecvHttpBody(Buffer* buf)
    {
        if(_recv_statu != RECV_HTTP_BODY) return false;
        // 获取正文长度
        size_t content_lenght = _request.ContentLength();
        // DBG_LOG("[CONTENT-LENGTH: %ld]",content_lenght);
        if(content_lenght == 0){
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        // 当前已经接受了多少正文 _request.body
        size_t real_len = content_lenght - _request._body.size();

        // 接受正文放到body中，但是也要考虑当前缓冲区中的数据，是否是全部的正文
        // 3.1缓冲区中数据包含当前请求的所有正文，则取出所需的
        if(buf->ReadAbleSize() >= real_len) {
            _request._body.append(buf->ReadPosition(),real_len);
            buf->MoveReadOffset(real_len);
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        // 3.2数据不足，取出数据，然后等待新数据到来 
        _request._body.append(buf->ReadPosition(),buf->ReadAbleSize());
        buf->MoveReadOffset(buf->ReadAbleSize());
        return true;
    } 
public:
    HttpContext():_resp_statu(200),_recv_statu(RECV_HTTP_LINE) {}
    void ReSet()
    {
        _resp_statu =200;
        _recv_statu = RECV_HTTP_LINE;
        _request.ReSet(); 
    }
    int RespStatu()
    {
        return _resp_statu;
    }
    HttpRecvStatu RecvStatu()
    {
        return _recv_statu;
    }
    HttpRequest& Request()
    {
        return _request;
    }
    void RecvHttpRequest(Buffer* buf) // 接受并解析http请求
    {
        // 不同的状态做不同的事情，不需要处理，因为需要将Buffer中的数据全部处理掉
        switch (_recv_statu)
        {
            case RECV_HTTP_LINE: RecvHttpLine(buf);
            case RECV_HTTP_HEAD: RecvHttpHead(buf);
            case RECV_HTTP_BODY: RecvHttpBody(buf);
        }
        return;
    }
};

class HttpServer{
private:
    using Handler = std::function<void(const HttpRequest&,HttpResponse*)>;
    using Handlers = std::vector<std::pair<std::regex,Handler>>;
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _delete_route;
    std::string _basedir;
    TcpServer _server;
private:
    void ErrorHandler(const HttpRequest& req,HttpResponse* rsp)
    {
        // 1.组织错误展示页面
        std::string body;
        body += "<html> <head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(rsp->_statu);
        body += " ";
        body += Util::StatusDesc(rsp->_statu);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        // 2.将页面数据当作展示正文，放入rsp这种
        rsp->SetContent(body);
    }
    void FileHandler(const HttpRequest& req,HttpResponse* rsp){ // 静态资源的请求处理
        std::string req_path = _basedir + req._path;
        if(req._path.back() == '/') {
            req_path += "index.html";
        }
        DBG_LOG("%s",req_path.c_str());
        bool ret = Util::ReadFile(req_path,&rsp->_body);
        std::string mime = Util::ExtMime(req_path);
        rsp->SetHeader("Content-Type",mime);
    }
    bool IsFileHandler(HttpRequest& req) {
        // 设置静态资源根目录
        if(_basedir.empty()) return false;
        DBG_LOG("%s",req._path.c_str());
        for(auto& it: req._params){
            DBG_LOG("[%s: %s]",it.first.c_str(),it.second.c_str());
        }
        // 请求方法 GET/HEAD
        if(req._method != "GET" && req._method != "HEAD") return false;
        // 请求的资源路径必须是一个合法的
        if(!Util::VaildPath(req._path)) return false;
        // 资源必须存在
        std::string req_path = _basedir + req._path;
        if(req._path.back() == '/') {
            req_path += "index.html";
        }
        if(!Util::IsRegular(req_path)) return false;
        return true;
    } 
    void WriteResponse(const PtrConnection& conn,HttpRequest& req,HttpResponse& rsp) // 将要素按照HttpResponse协议进行组织，再发送
    {
        // 完善头部字段
        if(req.Close()){
            DBG_LOG("CONNECTION IS CLOSE");
            rsp.SetHeader("Connection","close");
        }
        else{
            rsp.SetHeader("Connection","keep-alive");
            DBG_LOG("CONNECTION IS KEEP-ALIVE");
        }
        if(!rsp._body.empty() && !rsp.HasHeader("Content-Length")){
            rsp.SetHeader("Content-Length",std::to_string(rsp._body.size()));
        }
        if(!rsp._body.empty() && !rsp.HasHeader("Content-Type")){
            rsp.SetHeader("Content-Type","application/octet-stream");
        }
        if(rsp._redirect_flag) {
            rsp.SetHeader("Location",rsp._redirect_url);
        }
        // 将rsp完善，按照http协议格式进行组织
        std::stringstream rsp_str;
        rsp_str << req._version << " " << std::to_string(rsp._statu) << " " << Util::StatusDesc(rsp._statu) << "\r\n";
        for(auto &head:rsp._headers){
            rsp_str << head.first<<": " << head.second << "\r\n";
        }
        rsp_str << "\r\n";
        // DBG_LOG("%s",rsp._body.c_str());
        rsp_str << rsp._body;
        // 发送数据
        conn->Send(rsp_str.str().c_str(),rsp_str.str().size());
    }
    

    void Dispatcher(HttpRequest& req,HttpResponse* rsp,Handlers & handlers) // 功能性请求的分类处理
    {
        // 在请求方法的路由表中，查找对应的资源路径的处理函数，有则调用，没有则404
        // 思想：路由表储存的键值对 -- 正则表达式 处理函数
        // 使用正则表达式，对请求的资源路径进行 正则匹配，匹配成功就使用对应的函数进行处理
        // /number/(\d+) /number/1234
        for(auto& handler : handlers) {
            const std::regex& re = handler.first;
            const Handler &functor = handler.second;
            bool ret = std::regex_match(req._path,req._matches,re);
            if(!ret)
                continue;
            return functor(req,rsp); 
        }
        rsp->_statu = 404;

    }
    void Route(HttpRequest& req,HttpResponse* rsp)
    {
        // 对请求进行分辨，是静态资源的，还是功能性请求
        // GET HEAD 默认是静态资源的请求
        if(IsFileHandler(req)){
            // 静态资源请求
            return FileHandler(req,rsp);
        }
        if(req._method == "GET" || req._method == "HEAD") {
            return Dispatcher(req,rsp,_get_route);
        }else if(req._method == "POST") {
            return Dispatcher(req,rsp,_post_route);
        }else if(req._method == "PUT") {
            return Dispatcher(req,rsp,_put_route);
        }else if(req._method == "DELETE") {
            return Dispatcher(req,rsp,_delete_route);
        }
        rsp->_statu = 405;

    }
    void OnConnected(const PtrConnection& conn)//设置上下文
    {
        conn->SetContext(HttpContext());
        DBG_LOG("NEW CONNECTION %p",conn.get());
    }
    void OnMessage(const PtrConnection& conn,Buffer* buf) // 缓冲区数据解析+解析
    {
        while(buf->ReadAbleSize() > 0){
            // 1.获取上下文
            HttpContext* context = conn->GetContext()->get<HttpContext>();
            // 2.通过上下文对数据进行解析，得到httprequest对象
                // 如果缓冲区的数据解析出错，就直接回复错误信息
                // 解析请求，且请求处理完毕，才开始进行处理
            context->RecvHttpRequest(buf);
            HttpRequest &req = context->Request();
            HttpResponse rsp(context->RespStatu());
            if(context->RespStatu() >= 400){
                ErrorHandler(req,&rsp);
                WriteResponse(conn,req,rsp);
                context->ReSet();
                buf->MoveReadOffset(buf->ReadAbleSize()); // 出错就直接刷新缓冲区
                conn->Shutdown();
                return;
            }
            if(context->RecvStatu() != RECV_HTTP_OVER) {
                // 当前请求还没有接受完整
                return;
            }
            // 3.请求路由
            Route(req,&rsp);
            // 4.对httpresponse进行组织发送
            WriteResponse(conn,req,rsp);
            // 重置上下文
            context->ReSet();
            // 5.根据长短连接判断是关闭连接还是继续处理
            if(rsp.Close())
                conn->Shutdown();
        }
    }
public:
    HttpServer(int port,int timeout = DEFAULT_TIMEOUT):_server(port) {
        _server.EnableInactiveRelease(timeout);
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
    }
    void SetBaseDir(const std::string& path) {
        assert(Util::IsDirectory(path));
        _basedir = path;
    }
    void Get(const std::string& pattern,const Handler& handler)
    {
        _get_route.push_back({std::regex(pattern),handler});
    }
    void Post(const std::string& pattern,const Handler& handler)
    {
        _post_route.push_back({std::regex(pattern),handler});
    }
    void Put(const std::string& pattern,const Handler& handler)
    {
        _put_route.push_back({std::regex(pattern),handler});
    }
    void Delete(const std::string& pattern,const Handler& handler)
    {
        _delete_route.push_back({std::regex(pattern),handler});
    }
    void SetThreadCount(int cnt) {
        _server.SetThreadCount(cnt);
    }
    void Listen() {
        _server.Start();
    }
};